Matlab编程-- 向量化技术&似然概率
本篇博客的目标:对数似然概率公式的Matlab编程
对数似然概率公式:
lnp(X∣μ,Σ)=−21(Dln(2π)+ln∣Σ∣+(xn−μ)TΣ−1(xn−μ))
编程难点:公式中的x是列向量,而Matlab中的X是矩阵,为了提高代码的效率避免使用过多的for语句,这里使用向量化技术完成算法的编程任务。
公式推导
参考链接:https://www.cnblogs.com/ccienfall/p/6049021.html
多维高斯函数的似然概率:
N(x∣μ,Σ)=(2π)D/21∣Σ∣1/21exp{−21(x−μ)TΣ−1(x−μ)}
若是考虑数据集X=(x1,…,xN)T,再求对数则为:
lnp(X∣μ,Σ)=−2NDln(2π)−2Nln∣Σ∣−21n=1∑N(xn−μ)TΣ−1(xn−μ)
⭐️但是我需要的似然概率,xi在第k个分布下的似然概率:【实数】
N(xi∣μk,Σk)=(2π)D/21∣Σk∣1/21exp{−21(xi−μk)TΣk−1(xi−μk)}
展开后,得证:
lnp(X∣μ,Σ)==−2Dln(2π)−21ln∣Σ∣−21(xn−μ)TΣ−1(xn−μ)−21(Dln(2π)+ln∣Σ∣+(xn−μ)TΣ−1(xn−μ))
最终代码
function logprob = lgmmprob(data, mu, sigma, w)
ndim = size(data, 1); C = sum(mu.*mu./sigma) + sum(log(sigma)); D = (1./sigma)' * (data .* data) - 2 * (mu./sigma)' * data + ndim * log(2 * pi); logprob = -0.5 * (bsxfun(@plus, C', D)); logprob = bsxfun(@plus, logprob, log(w));
|
舍弃系数-0.5,进一步简化需要编程的部分:
Dln(2π)+ln∣Σ∣+(xi−μk)TΣk−1(xi−μk)
需要说明的是上面所有的小项都是实数。
向量化技术⭐️
1. 改造公式
Σ在数学推导中的公式中是 full−variance 矩阵,但是一般代码中的协方差矩阵默认是对角协方差矩阵。故这里就存在一个算法和实际编程中的一个不匹配的地方,故这个时候需要对原本的算法公式进行改造
(a1,a2)∗(Δ100Δ2)∗(a1a2)=Δ1a12+Δ2a22
(Δ1,Δ2)∗(a1a2).∗(a1a2)=Δ1a12+Δ2a22
故原先的第三项为:(xi−μk)TΣk−1(xi−μk)
其中令Σ是一个列向量,可以见下节的变量维度说明。(Δ1,Δ2)=(Σk−1)T
(Σk−1)T∗(xi−μk).∗(xi−μk)
Dln(2π)+ln∣Σk∣+(Σk−1)T∗[xi .∗ xi−2μk .∗ xi+μk .∗ μk]
2. 变量维度说明:
xi:(p,1)
X={x1,x2,…,xi,…,xn}:(p,n)
Σk:(p,1)
Σ={Σ1,Σ2,…,Σk,…,ΣK}:(p,K)
μk:(p,1)
μ={μ1,μ2,…,μk,…,μK}:(p,K)
3. 列向量改矩阵⭐️
这个是最关键的一步,一步一步解答,以便下次遇到的时候可以轻松应对,上式是原数学方程式中的数学向量,但为了编程,需要向量化。
- 首先明确向量化的目的:用Σ,μ,X代替Σk,μk,xi
- 其次明确维度:每一项的都是实数
这里再明确一下待编程的方程为:
Dln(2π)+ln∣Σk∣+(Σk−1)T∗[xi .∗ xi−2μk .∗ xi+μk .∗ μk]
根据每一小项是否与分布k和样本i有关可进一步划分:
|
与k有关 |
与k无关 |
与i有关 |
1. k与i 矩阵乘 2. k 与 i 点乘,需转换为矩阵乘 3. 不满足以上两个条件 |
|
与i无关 |
ln∥Σk−1∥ |
Dln(2π) |
- 情况一:与k和i都无关的项,Dln(2π):实数
-
情况二:仅与k有关的项,ln∣Σk−1∣: 实数
这里试求方差的行列式,又方差是对角矩阵,所以可简化为:
ln∣(Δ100Δ2)∣=ln∣Δ1⋅Δ2∣=lnΔ1+lnΔ2=sum(ln(Δ1,Δ2))
ln∣Σk∣=sum(Σk):(1,1):
可以向右扩展:
{sum(Σ1),sum(Σ2),…,sum(Σk)}=sum(Σ):(1,k)
-
情况三:k与i已经分开,且由矩阵乘相连
(Σk−1)T∗[xi .∗ xi]:(p,1)T∗(p,1).∗(p,1)=(1,1)实数
向量化具体细节讲解:
元素向量化:将xi横向扩展,将Σk纵向扩展
{(Σk−1)Tx1.∗x1,(Σk−1)Tx2.∗x2,…,(Σk−1)Txn.∗xn}=(Σk−1)T∗{x1.∗x1, x2.∗x2, …,xn.∗xn}=(Σk−1)T∗(X.∗X):(1,p)∗(p,n)=(1,n)还可以向上下扩展=((Σ1−1,Σ2−1,…,ΣK−1))T∗(X.∗X)=(Σ−1)T∗(X.∗X):(k,n)
- 情况四:k和i为点乘,需要转换为矩阵乘:(Σk−1)T∗[−2μk.∗xi]:(p,1)T∗(p,1)=(1,1)实数
但此时有个问题,无法进行向量化,因为这里的运算规则必须先进行点乘运算,再进行矩阵乘运算,若需向量化中间必须用矩阵乘相连,原因后面解释。
−2∗(Σk−1)T.∗μkT∗xi=−2(Σk−1.∗μk)T∗xi
向量化处理同情况三:直接去掉下标即可
−2(Σ−1.∗μ)T∗X
- 情况五:都为k,中间既有矩阵乘又有点乘
(Σk−1)T∗μk .∗ μk:(p,1)T(p,1)=(1,1)
将矩阵乘转换为点乘:(Σk−1)T∗μk .∗ μk=sum(Σk−1.∗μk.∗μk)
对于一些细节的补充:
-
为啥必须为矩阵乘来连接两个部分,举例如下:
若:X=(x1,x2,…,xn)
(Ax1,Ax2,…,Axn)=A∗(x1,x2,…,xn)=A∗X
而点乘则不满足这条性质:
(A.∗x1,A.∗x2,…,A.∗xn)∗(x1,x2,…,xn)=A∗X
-
为啥情况五中,不允许出现点乘?
fifth={(Σ1−1)T∗(μ.∗μ1),(Σ2−1)T∗(μ2.∗μ2),…,(Σk−1)T∗(μk.∗μk)}
根据向量化的定理,根本没办法凑出一个完整的矩阵如μ,若直接去除下标则为:
(Σ−1)T∗μ.∗μ:(p,k)T(p,k)=(k,k)
上式肯定不可能办到,因为向量化同一个小标只能往一个方向扩展,即应为(1,k)